package server;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

public class Server extends Thread {

	public static int TIMEOUT = 20000;
	private BufferedInputStream cis, sis;
	private BufferedOutputStream cos, sos;
	private Socket csocket;
	public static  int threadid = 0;

	public Server(Socket socket) throws IOException {
		csocket = socket;
		System.out.println("--start start up");

	}
	public void run(){
		try {
			Proxy(csocket);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void Proxy(Socket socket) throws IOException {
		cis = new BufferedInputStream(socket.getInputStream());
		cos = new BufferedOutputStream(socket.getOutputStream());
		Request request = paresHead(cis);
//		System.out.println(request);
		Socket Ssocket = serverLink(request);
		if(Ssocket == null) return;
		sis = new BufferedInputStream(Ssocket.getInputStream());
		sos = new BufferedOutputStream(Ssocket.getOutputStream());
		sendToServer(sos, request);
		System.out.println("--recive from server " + request.getServerURL() + ":" + request.getPort());
		PipToCilent();
	}

	private void PipToCilent() throws IOException {
		ThreadIn in = new ThreadIn(sis, cos,threadid );
		ThreadOut out = new ThreadOut(cis, sos,threadid ++);
		in.start();
		out.start();
	}

	private Response recivFromServer(InputStream sis2) throws IOException {
		// TODO Auto-generated method stub
		int buf = 0;
		StringBuilder sb = new StringBuilder();
		int flag = 0;
		Response resp = new Response();
	
			while ((buf = sis2.read()) != -1) {
				System.out.print((char)buf);
				
			}
		
		while (true) {
			sb.delete(0, sb.length());
			while ((buf = sis2.read()) != -1) {
				if (buf == '\r') {
					sis2.read();
					break;
				}
				sb.append((char) buf);
			}
			if (flag == 0) {
				resp.setFirstLine(sb.toString());
				flag++;
			} else {
				String[] strs = sb.toString().split(":");
				if (strs.length < 2) {
					break;
				}
				resp.addAttr(strs[0], strs[1].trim());
			}
		}
		// 读取主体内容
		StringBuilder content = new StringBuilder();
		flag = 0;
		while (true) {
			sb.delete(0, sb.length());
			while ((buf = sis2.read()) != -1) {
				System.out.print((char)buf);
//				if (buf == '\r') {
//					sis2.read();
//					break;
//				}
//				System.out.print((char) buf);
//				sb.append((char) buf);
			}
			if(buf == -1)
				break;
			if (sb.length() == 0) {
				flag = 1;
		//		continue;
			} else if (sb.equals("0") && flag == 1) {
				flag = 0;
				break;
			}
			content.append(sb);
		}
		return resp;

	}

	private void sendToServer(OutputStream os, Request request)
			throws IOException {
		os.write(request.toString().getBytes());
		os.flush();
	}

	private Socket serverLink(Request request) throws UnknownHostException,
			IOException {
		// TODO Auto-generated method stub
		String url = request.getServerURL();
		if (request.getServerURL() == null) {
			return null;
		}
		Socket socket = new Socket(url, request.getPort());
		socket.setSoTimeout(TIMEOUT);

		return socket;
	}

	private Request paresHead(BufferedInputStream cis2) throws IOException {
		// TODO Auto-generated method stub
		StringBuilder sb = new StringBuilder();
		Request request = new Request();
		int buf;
		int flag = 0;
		while (true) {
			sb.delete(0, sb.length());
			while ((buf = cis2.read()) != -1) {
				if (buf == '\r') {
					// 读掉\n
					cis2.read();
					break;
				}
				sb.append((char) buf);
			}
			if (flag == 0 && sb.length() > 1) {
				request.setFirstLine(sb.toString());
				String[] strs = sb.toString().split(" ");
				request.setMethod(strs[0]);
//				System.out.println("--setServerURL " + strs[1]);
				request.setServerURL(strs[1]);
				flag++;
			} else {
				String[] strs = sb.toString().split(":");
				if (strs.length < 2)
					break;
				request.addAttr(strs[0], strs[1].trim());
			}
		}

		return request;
	}

	public static void main(String[] args) throws IOException {
		ServerSocket server = new ServerSocket(8087);
		while(true){
			Socket socket = server.accept();
			socket.setSoTimeout(Server.TIMEOUT);
			Server s = new Server(socket);
			s.start();
		}
		
		
	}
}

class Request {
	String ENDFLAG = "\r\n";
	LinkedHashMap<String, String> httpHead = new LinkedHashMap<String, String>();
	String firstLine; // 第一行数据
	String method;
	String serverURL;
	boolean absolutPath = false;
	// 可能存在的端口，默认80
	int port = 80;

	public int getPort() {
		return port;
	}

	public void setFirstLine(String string) {
		// TODO Auto-generated method stub
		this.firstLine = string;
	}

	public String getFirstLine() {
		return firstLine;
	}

	public String getMethod() {
		return method;
	}

	public void setMethod(String method) {
		this.method = method;
	}

	public String getServerURL() {
		if(!this.absolutPath){
			return this.httpHead.get("Host");
		}
		return serverURL;
	}

	public void setServerURL(String serverURL) {
		String str = serverURL;
		if(serverURL.indexOf("/") != 0)
			this.absolutPath = true;
		int i;
		i = str.indexOf("//");
		if (i > -1) {
			str = serverURL.substring(i + 2);
			if (str.indexOf("/") > -1)
				str = str.substring(0, str.indexOf("/"));
		}
		i = str.indexOf(":");
		if (i > -1) {
			this.port = Integer.parseInt(serverURL.substring(i + 1,
					serverURL.length()));
			System.out.println("---set port " + this.port);
			str = str.substring(0,i);
		}
		

		this.serverURL = str;
	}

	public String getAttr(String param) {
		return httpHead.get(param);
	}

	public void addAttr(String param, String val) {
		httpHead.put(param, val);
	}

	public String toString() {
		StringBuilder strb = new StringBuilder();
		Iterator it = httpHead.entrySet().iterator();
		strb.append(this.firstLine).append(this.ENDFLAG);
		while (it.hasNext()) {
			Map.Entry entity = (Entry) it.next();
			// System.out.println("[ key = " + entity.getKey() +
			// ", value = " + entity.getValue() + " ]");
			strb.append(entity.getKey()).append(": ").append(entity.getValue())
					.append(ENDFLAG);
		}
		strb.append(ENDFLAG);
		return strb.toString();
	}

}

class Response {
	String ENDFLAG = "\r\n";
	LinkedHashMap<String, String> httpHead = new LinkedHashMap<String, String>();
	String firstLine; // 第一行数据
	String content;

	public String getAttr(String param) {
		return httpHead.get(param);
	}

	public void addAttr(String param, String val) {
		httpHead.put(param, val);
	}

	public String getFirstLine() {
		return firstLine;
	}

	public void setFirstLine(String firstLine) {
		this.firstLine = firstLine;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String toString() {
		StringBuilder strb = new StringBuilder();
		Iterator it = httpHead.entrySet().iterator();
		strb.append(this.firstLine).append(this.ENDFLAG);
		while (it.hasNext()) {
			Map.Entry entity = (Entry) it.next();
			strb.append(entity.getKey()).append(": ").append(entity.getValue())
					.append(ENDFLAG);
		}
		// 发送终止标志
		strb.append(ENDFLAG);
		strb.append("0");
		strb.append(ENDFLAG);
		return strb.toString();
	}
}
